{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h1> Getting started with TensorFlow </h1>\n",
    "\n",
    "In this notebook, you play around with the TensorFlow Python API."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import tensorflow as tf\n",
    "import numpy as np\n",
    "\n",
    "print(tf.__version__)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2> Adding two tensors </h2>\n",
    "\n",
    "First, let's try doing this using numpy, the Python numeric package. numpy code is immediately evaluated."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.array([5, 3, 8])\n",
    "b = np.array([3, -1, 2])\n",
    "c = np.add(a, b)\n",
    "print(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The equivalent code in TensorFlow consists of two steps:\n",
    "<p>\n",
    "<h3> Step 1: Build the graph </h3>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = tf.constant([5, 3, 8])\n",
    "b = tf.constant([3, -1, 2])\n",
    "c = tf.add(a, b)\n",
    "print(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "c is an Op (\"Add\") that returns a tensor of shape (3,) and holds int32. The shape is inferred from the computation graph.\n",
    "\n",
    "Try the following in the cell above:\n",
    "<ol>\n",
    "<li> Change the 5 to 5.0, and similarly the other five numbers. What happens when you run this cell? </li>\n",
    "<li> Add an extra number to a, but leave b at the original (3,) shape. What happens when you run this cell? </li>\n",
    "<li> Change the code back to a version that works </li>\n",
    "</ol>\n",
    "\n",
    "<p/>\n",
    "<h3> Step 2: Run the graph"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with tf.Session() as sess:\n",
    "  result = sess.run(c)\n",
    "  print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2> Using a feed_dict </h2>\n",
    "\n",
    "Same graph, but without hardcoding inputs at build stage"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = tf.placeholder(dtype=tf.int32, shape=(None,))\n",
    "b = tf.placeholder(dtype=tf.int32, shape=(None,))\n",
    "c = tf.add(a, b)\n",
    "with tf.Session() as sess:\n",
    "  result = sess.run(c, feed_dict={\n",
    "    a: [3, 4, 5],\n",
    "    b: [-1, 2, 3]\n",
    "  })\n",
    "  print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2> Heron's Formula in TensorFlow </h2>\n",
    "\n",
    "The area of triangle whose three sides are $(a, b, c)$ is $\\sqrt{s(s-a)(s-b)(s-c)}$ where $s=\\frac{a+b+c}{2}$ \n",
    "\n",
    "Look up the available operations at https://www.tensorflow.org/api_docs/python/tf"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def compute_area(sides):\n",
    "  # slice the input to get the sides\n",
    "  a = sides[:,0]  # 5.0, 2.3\n",
    "  b = sides[:,1]  # 3.0, 4.1\n",
    "  c = sides[:,2]  # 7.1, 4.8\n",
    "  \n",
    "  # Heron's formula\n",
    "  s = (a + b + c) * 0.5   # (a + b) is a short-cut to tf.add(a, b)\n",
    "  areasq = s * (s - a) * (s - b) * (s - c) # (a * b) is a short-cut to tf.multiply(a, b), not tf.matmul(a, b)\n",
    "  return tf.sqrt(areasq)\n",
    "\n",
    "with tf.Session() as sess:\n",
    "  # pass in two triangles\n",
    "  area = compute_area(tf.constant([\n",
    "      [5.0, 3.0, 7.1],\n",
    "      [2.3, 4.1, 4.8]\n",
    "    ]))\n",
    "  result = sess.run(area)\n",
    "  print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<h2> Placeholder and feed_dict </h2>\n",
    "\n",
    "More common is to define the input to a program as a placeholder and then to feed in the inputs. The difference between the code below and the code above is whether the \"area\" graph is coded up with the input values or whether the \"area\" graph is coded up with a placeholder through which inputs will be passed in at run-time."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with tf.Session() as sess:\n",
    "  sides = tf.placeholder(tf.float32, shape=(None, 3))\n",
    "  area = compute_area(sides)\n",
    "  result = sess.run(area, feed_dict = {\n",
    "    sides: [\n",
    "      [5.0, 3.0, 7.1], \n",
    "      [2.3, 4.1, 4.8]\n",
    "    ]\n",
    "  })\n",
    "  print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## tf.eager\n",
    "\n",
    "tf.eager allows you to avoid the build-then-run stages. However, most production code will follow the lazy evaluation paradigm because the lazy evaluation paradigm is what allows for multi-device support and distribution. \n",
    "<p>\n",
    "One thing you could do is to develop using tf.eager and then comment out the eager execution and add in the session management code.\n",
    "\n",
    "<b> To run this block, you must first reset the notebook using Reset on the menu bar, then run this block only. </b>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/usr/local/envs/py3env/lib/python3.5/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.\n",
      "  from ._conv import register_converters as _register_converters\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tf.Tensor([6.278497 4.709139], shape=(2,), dtype=float32)\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "from tensorflow.contrib.eager.python import tfe\n",
    "\n",
    "tfe.enable_eager_execution()\n",
    "\n",
    "def compute_area(sides):\n",
    "  # slice the input to get the sides\n",
    "  a = sides[:,0]  # 5.0, 2.3\n",
    "  b = sides[:,1]  # 3.0, 4.1\n",
    "  c = sides[:,2]  # 7.1, 4.8\n",
    "  \n",
    "  # Heron's formula\n",
    "  s = (a + b + c) * 0.5   # (a + b) is a short-cut to tf.add(a, b)\n",
    "  areasq = s * (s - a) * (s - b) * (s - c) # (a * b) is a short-cut to tf.multiply(a, b), not tf.matmul(a, b)\n",
    "  return tf.sqrt(areasq)\n",
    "\n",
    "area = compute_area(tf.constant([\n",
    "      [5.0, 3.0, 7.1],\n",
    "      [2.3, 4.1, 4.8]\n",
    "    ]))\n",
    "\n",
    "print(area)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Copyright 2017 Google Inc. Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
